﻿using System;
using System.Configuration;
using System.Data;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Nvigorate.Relational.Mapping.Fluent;
using Nvigorate.Relational.Mapping.Index;
using Nvigorate.Relational.Navigation;
using Nvigorate.Relational.Repository;

namespace Nvigorate.Test.Relational.Binding
{
    /// <summary>
    /// Summary description for DiscriminationTests
    /// </summary>
    [TestClass]
    public class DiscriminationTests
    {
        protected DataSet _set;
        protected DataTable _table;
        protected IRepositoryMapIndex _index;

        public DiscriminationTests()
        {
            _set = new DataSet("IVehicleSet");
            _table = _set.Tables.Add("IVehicle");
            _table.Columns.Add("Vehicle.Type");
            _table.Columns.Add("Vehicle.Make");
            _table.Columns.Add("Vehicle.Model");
            _table.Columns.Add("Vehicle.Year");

            _table.Rows.Add("Car", "Honda", "Civic", "2008");
            _table.Rows.Add("Truck", "Nissan", "Titan", "2008");
            _table.Rows.Add("Boat", "Snooderberger", "BadgerSlap", "2008");

            _index = new MapIndexFactory(ConfigurationManager.GetSection("MapConfiguration") as MapConfigurationSection).CreateMapIndex().GetRepositoryMapIndex("simple");
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        public void TestDeadSimpleDiscrimination()
        {
            var navigator = new PersistableTypeNavigator(typeof (IVehicle), null, _index);
            var binder = new PersistableTypeBinder<IVehicle>(_index, _set);
            navigator.Accept(binder);

            var instanceses = binder.Instances;

            Assert.AreEqual(1, instanceses.OfType<Car>().Count());
            Assert.AreEqual(1, instanceses.OfType<Truck>().Count());
            Assert.AreEqual(1, instanceses.OfType<Boat>().Count());
        }

        [TestMethod]
        public void TestFilteredDiscrimination()
        {
            _set.Tables[0].TableName = "Car";
            var navigator = new PersistableTypeNavigator(typeof(Car), null, _index);
            var binder = new PersistableTypeBinder<Car>(_index, _set);
            navigator.Accept(binder);

            var instanceses = binder.Instances;

            Assert.IsTrue(instanceses.All(i => i.GetType().Equals(typeof(Car))));
            Assert.AreEqual(1, instanceses.Count());
        }
    }

    public interface IVehicle
    {
        string Make { get; set; }
        string Model { get; set; }
        string Year { get; set; }
    }

    public abstract class VehicleBase : IVehicle
    {
        public virtual string Make { get; set; }
        public virtual string Model { get; set; }
        public virtual string Year { get; set; }
    }

    public class Car : VehicleBase { }

    public class Truck : VehicleBase { }

    public class Boat : VehicleBase { }

    public class VehicleMap : FluentMap<IVehicle>
    {
        public VehicleMap()
        {
            RepositoryName = "simple";
            var table = MapTable("Vehicle");

            table.Assign(v => v.Make);
            table.Assign(v => v.Model);
            table.Assign(v => v.Year);

            DiscriminateOnColumnValue()
                .RegisterType<Car>("Type", "Vehicle", "Car")
                .RegisterType<Truck>("Type", "Vehicle", "Truck")
                .RegisterType<Boat>("Type", "Vehicle", "Boat");
        }
    }

    public class CarMap : FluentMap<Car>
    {
        public CarMap()
        {
            InheritMap<VehicleMap, IVehicle>();

        }
    }

    public class TruckMap : FluentMap<Truck>
    {
        public TruckMap()
        {
            InheritMap<VehicleMap, IVehicle>();

        }
    }

    public class BoatMap : FluentMap<Boat>
    {
        public BoatMap()
        {
            InheritMap<VehicleMap, IVehicle>();

        }
    }
}
